#include <SDL2/SDL.h>
#include <iostream>

// sdl初始化并创建窗口
bool init();

// 加载图片
bool loadMedia();

// 关闭sdl并释放资源
void close();

// 加载单个图片
SDL_Surface* loadSurface( std::string path );

// 渲染的窗口
SDL_Window * gWindow = nullptr;

// 窗口表面
SDL_Surface * gScreenSurface = nullptr;

// 当前展示的图片
SDL_Surface * gCurrentSurface = nullptr;

const int SCREEN_WIDTH = 640;
const int SCREEN_HEIGHT = 480;

bool init()
{
     //Initialization flag
    bool success = true;

    //Initialize SDL
    if( SDL_Init( SDL_INIT_VIDEO ) < 0 )
    {
        char str[1024];
        sprintf(str, "SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
        std::cout << str << std::endl;
        success = false;
    }
    else
    {
        //Create window
        gWindow = SDL_CreateWindow( "SDL Tutorial", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_SHOWN );
        if( gWindow == nullptr )
        {
            char str[1024];
            sprintf(str, "Window could not be created! SDL_Error: %s\n", SDL_GetError());
            std::cout << str << std::endl;
            success = false;
        }
        else
        {
            //Get window surface
            gScreenSurface = SDL_GetWindowSurface( gWindow );
        }
    }

    return success;
}

SDL_Surface* loadSurface( std::string path )
{
    //The final optimized image
    SDL_Surface* optimizedSurface = nullptr;

    //Load image at specified path
    SDL_Surface* loadedSurface = SDL_LoadBMP( path.c_str() );
    if( loadedSurface == nullptr )
    {
        char str[1024];
        sprintf(str, "Unable to load image %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
        std::cout << str << std::endl;
    }
    else
    {
        /*
            当加载位图时，通常会以 24bit 格式加载，因为大多数位图都是 24bit。大多数现代显示器默认不是 24 位。如果我们将 24bit 的图像加载到 32bit 的屏幕中，
            SDL 将在每次加载图像时对其进行转换。因此，我们要做的是在加载图像时将其转换为与屏幕相同的格式，这样就无需在闪存时进行转换。
            这可以通过 SDL_ConvertSurface 轻松实现。我们所要做的就是将我们要转换的曲面传入屏幕格式
        */
        optimizedSurface = SDL_ConvertSurface( loadedSurface, gScreenSurface->format, 0 );
        if( optimizedSurface == nullptr )
        {
            char str[1024];
            sprintf(str, "Unable to optimize image %s! SDL Error: %s\n", path.c_str(), SDL_GetError());
            std::cout << str << std::endl;
        }

        //SDL_ConvertSurface 返回的是一个新格式的原始图像副本。调用后，加载的原始图像仍保留在内存中。这意味着我们必须释放原始载入的曲面，否则内存中就会有两份相同的图像
        SDL_FreeSurface( loadedSurface );
    }

    return optimizedSurface;
}

bool loadMedia()
{
    //Loading success flag
    bool success = true;

    //Load default surface
    gCurrentSurface = loadSurface( "stretch.bmp" );
    if( gCurrentSurface == nullptr )
    {
        std::cout << "Failed to load default image!" << std::endl;
        success = false;
    }

    return success;
}

void close()
{
    // 释放资源  

    //Deallocate surface
    SDL_FreeSurface( gCurrentSurface );
    gCurrentSurface = nullptr;

    //Destroy window
    SDL_DestroyWindow( gWindow );
    gWindow = nullptr;

    //Quit SDL subsystems
    SDL_Quit();
}


int main( int argc, char* args[] )
{
    //Start up SDL and create window
    if( !init() )
    {
        std::cout << "Failed to initialize!" << std::endl;
    }
    else
    {
        //Load media
        if( !loadMedia() )
        {
            std::cout << "Failed to load media!" << std::endl;
        }
        else
        {
            /*
                SDL 2 新增了一个专用函数，用于将图像拉伸为不同尺寸：SDL_BlitScaled。与之前的混合图像一样，SDL_BlitScaled 接收一个要加载到目标表面上的源表面。
                它还接收一个目标 SDL_Rect，该区域定义了要混合的图像的位置和大小。
                因此，如果我们要将小于屏幕的图像变成屏幕的大小，就需要将目标的宽度/高度设为屏幕的宽度/高度。
            */
            //Apply the image stretched
            SDL_Rect stretchRect;
            stretchRect.x = 0;
            stretchRect.y = 0;
            stretchRect.w = SCREEN_WIDTH;
            stretchRect.h = SCREEN_HEIGHT;
            // SDL_BlitSurface( gCurrentSurface, nullptr, gScreenSurface, nullptr );  //不拉伸
            SDL_BlitScaled( gCurrentSurface, nullptr, gScreenSurface, &stretchRect );   // 拉伸
        
            //Update the surface
            SDL_UpdateWindowSurface( gWindow );

            //Hack to get window to stay up
            SDL_Event e; 
            bool quit = false; 

            //While application is running
            while( !quit )
            {
                //Handle events on queue
                while( SDL_PollEvent( &e ) != 0 )
                {
                    //User requests quit
                    if( e.type == SDL_QUIT )
                    {
                        quit = true;
                    }
                }
            }
        }
    }

    //Free resources and close SDL
    close();

    return 0;
}


